# coding=utf8
from pyglet.gl import *
import pyglet
import squirtle
class SignalInterface:
  def __init__(self):
    self.channels = {}
  def subscribe_to(self,channel,ob):
    #print ob
    if channel not in self.channels:
      self.channels[channel] = [ob]
    else:
      self.channels[channel].append(ob)
    
  def send(self,channel,values):
    #print channel
    if channel in self.channels:
      for listener in self.channels[channel]:
        print values
        listener.recieve(values)
  

common_signals = SignalInterface()

class Skin:
    def __init__(self):
      self.elements = {}
      self.elements['button'] = squirtle.SVG("graphics/button.svg")
      self.elements['bar'] =  squirtle.SVG("graphics/bar.svg")
      self.elements['tip'] =  squirtle.SVG("graphics/tooltip.svg")
      self.elements['frame'] =  squirtle.SVG("graphics/frame.svg")
    def ref(self,name):
      return self.elements[name]

default_skin = Skin()

#Draws layered graphics to avoid Z-fighting
class Layer:
  def __init__(self,layer_count):
    self.static_elements = []
    self.dynamic_elements = []
    
#We need to attach signal to window
class HierarchicalSignal:
  def __init__(self,window,rect):
    self.rect_link = rect
    self.window = window
    self.on_mouse_press_widgets = []
    self.on_mouse_release_widgets = []
    self.on_key_press_widgets = []
    self.on_key_release_widgets = []
    self.on_mouse_drag_widgets = []
    self.on_mouse_move_widgets = []
    self.on_text_widgets = []
    
    
    @self.window.event
    def on_mouse_press(x,y,button,mod):
      for widget in self.on_mouse_press_widgets:
        if widget.hit_test(x,y):
          widget.mouse_press(x,y,button)
      return False
    
    @self.window.event
    def on_mouse_release(x,y,button,mod):
      for widget in self.on_mouse_release_widgets:
        #if widget.hit_test(x,y):
        widget.mouse_release(x,y,button)
    @self.window.event
    def on_mouse_motion(x,y,dx,dy):
      for widget in self.on_mouse_move_widgets:
        if widget.hit_test(x,y) and widget.visible:
          widget.mouse_move(x,y,dx,dy) 
    
    @self.window.event
    def on_key_press(key,modifiers):
      for widget in self.on_key_press_widgets:
        widget.key_press(key,modifiers)
        
    @self.window.event
    def on_key_release(key,modifiers):
      for widget in self.on_key_release_widgets:
        widget.key_release(key,modifiers)
      
    @self.window.event
    def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
      for widget in self.on_mouse_drag_widgets:
        #if widget.hit_test(x,y):
        widget.mouse_drag(x,y,dx,dy,buttons,modifiers)
        
    @self.window.event
    def on_text_motion_select(text):
      pass
      
    @self.window.event
    def on_text_motion(text):
      for widget in self.on_text_widgets:
        widget.text_motion(text)
      
    @self.window.event
    def on_text(text):
        for widget in self.on_text_widgets:
          widget.text(text)
    
  def listen_to(self,signal):
    pass
  
  def stop_signal(self,signal):
    pass
    
  def hit_test(self,x,y):
    if x < self.rect[0]:
      return False
    if y < self.rect[1]:
      return False
    if x > self.rect[0]+self.rect[2]:
      return False
    if y > self.rect[1]+self.rect[3]:
      return False
    return True
    
class Widget:
  def __init__(self,name = 'widget',pos = (0,0),size = (0,0),skin=default_skin,consuming = True):
    self.visible = True
    self.name = name
    self.rect = None
    self.pos = 0,0
    self.size = 0,0
    self.skin = skin
    self.focused_wiget = None
    self.consuming = consuming
    self.type = 'attached'
    
  def dynamic_widgets(self):
    return None
    
  def update_rect(self):
    self.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1])
  
  def hit_test(self,x,y):
    if x < self.rect[0]:
      return False
    if y < self.rect[1]:
      return False
    if x > self.rect[0]+self.rect[2]:
      return False
    if y > self.rect[1]+self.rect[3]:
      return False
    return True
    
  def draw(self,style):
    pass
  def mouse_press(self,x,y,button):
    pass
  def focus(self):
    pass
  def unfocus(self):
    pass

class Layout(Widget):
  def __init__(self,rect):
    Widget.__init__(self)
    self.rect = rect
    self.widgets = []
    self.focused_widget = None
    self.batch = pyglet.graphics.Batch()
    self.batch.visible = True
    self.layers = [[],[],[]]
    self.layers[1].append(self.batch)
    self.visible = True
    
  def set_clipping(self):
    glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    # Disable clipping planes to check culling.
    glEnable(GL_CLIP_PLANE0)
    glEnable(GL_CLIP_PLANE1)
    glEnable(GL_CLIP_PLANE2)
    glEnable(GL_CLIP_PLANE3)
    # Left
    glClipPlane(GL_CLIP_PLANE0, (GLdouble * 4)(
                1, 0, 0, -(self.rect[0])))
    # Top
    glClipPlane(GL_CLIP_PLANE1, (GLdouble * 4)(
                0, -1, 0, self.rect[1] + self.rect[3]))
    # Right
    glClipPlane(GL_CLIP_PLANE2, (GLdouble * 4)(
                -1, 0, 0, self.rect[0] + self.rect[2] + 1))
    # Bottom
    glClipPlane(GL_CLIP_PLANE3, (GLdouble * 4)(
                0, 1, 0, -(self.rect[1])))
  
  def unset_clipping(self):
    glPopAttrib()
  
  def add_widget(self,widget):
    self.widgets.append(widget)
    self.update_layout()
    self.layers[0].append(widget)
    if widget.dynamic_widgets() is not None:
      self.layers[1].append(widget.dynamic_widgets())
    
  def set_pos (self,x,y):
    self.rect = x,y,self.rect[2],self.rect[3]
    #self.update_layout()
  
  def update_layout(self):
    pass
    
  def switch_focus(self,widget):
    if self.focused_widget is not None:
      self.focused_widget.unfocus()
    self.focused_widget = widget
    self.widgets.remove(self.focused_widget)
    self.widgets.insert(0,self.focused_widget)
    widget.focus()
    
  def set_focus(self,widget):
    if self.focused_widget is not None:
      self.focused_widget.unfocus()
    self.focused_widget = widget
    widget.focus()
    
  def draw(self):
    self.set_clipping()
    for layer in self.layers:
      for el in layer:
        if el.visible:
          el.draw()
    self.unset_clipping()
    #self.batch.draw()
    
  def key_press(self,button,modifiers):
    if self.focused_widget is not None:
      self.focused_widget.key_press(button,modifiers)
  
  def key_release(self,button,modifiers):
    if self.focused_widget is not None:
      self.focused_widget.key_release(button,modifiers)
  
  def mouse_press(self,x,y,button):
    if self.hit_test(x,y):
      for widget in self.widgets:
        if widget.hit_test(x,y) and widget.visible:
          if widget.mouse_press(x,y,button):
            if widget.type == 'floating':
              self.switch_focus(widget)
            else:
              self.set_focus(widget)

            if self.consuming:
              return
      
  def mouse_release(self,x,y,button):
    #for widget in self.widgets:
      if self.focused_widget is not None:
        self.focused_widget.mouse_release(x,y,button)
        if self.consuming:
          return
          
  def text(self,text):
    if self.focused_widget is not None:
      self.focused_widget.text(text)
  
  def text_motion(self,text):
    if self.focused_widget is not None:
      self.focused_widget.text_motion(text)
      
  def mouse_move(self,x,y,dx,dy):
    if self.hit_test(x,y):
      for widget in self.widgets:
          if widget.hit_test(x,y) and widget.visible:
            widget.on_mouse_move(x,y,dx,dy)
          else:
            widget.on_mouse_outside(x,y,dx,dy)
          
  
  def mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    if self.hit_test(x,y):
      for widget in self.widgets:
          if self.focused_widget == widget:
            self.focused_widget.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
          else:
            pass
  
  def subscribe_to(self,event_provider):
    event_provider.on_mouse_press_widgets.append(self)
    event_provider.on_mouse_release_widgets.append(self)
    event_provider.on_mouse_drag_widgets.append(self)
    event_provider.on_mouse_move_widgets.append(self)
    event_provider.on_text_widgets.append(self)
            
class GridLayout(Layout):
  def __init__(self,name,rect,size = (1,1),step = (0,0)):
    Layout.__init__(self,rect)
    self.step = step
    self.size = size
    
  def update_layout(self):
    counter = 0
    
    if self.step == (0,0):
      self.step = self.rect[2]/size[0],self.rect[3]/size[1]
    counter=0
    for widget in self.widgets:
      widget.pos =  5 + self.step[0] * int(counter%self.size[0]) + self.rect[0], self.rect[3] - self.step[1] -self.step[1] * int(counter/self.size[1])+self.rect[1]
      counter+=1
      widget.update_rect()
    
class CentralLayout(Layout):
  def __init__(self,name,rect,spacing  = 5.0,max_size_align = False):
    Layout.__init__(self,rect)
    self.max_size_align = True
    self.spacing = spacing
  
  #getting the elements 
  def update_layout(self):
    all_widget_size = 0
    max_size = 0
    for widget in self.widgets:
      all_widget_size += widget.size[1]+self.spacing
      if widget.size[0] > max_size:
        max_size = widget.size[0]
    pos = self.rect[3]/2.0+all_widget_size/2.0
    
    for widget in self.widgets:
      if self.max_size_align and widget.size == (0,0):
        widget.size = max_size,widget.size[1]
      pos  -= widget.size[1]+self.spacing
      
      x = (self.rect[2])/2.0 - widget.size[0]/2.0 + self.rect[0]
      y = pos +self.rect[1]
      widget.pos = x,y
      widget.update_rect()
      
  def draw(self):
    for widget in reversed(self.widgets):
      widget.draw()
     

class Bar(Widget):
  def __init__(self,caption,pos = (0,0),size = (0,0),skin = default_skin,on_drag = None):
    Widget.__init__(self,caption,pos,size)
    self.pos = pos
    self.size = size
    self.on_drag = on_drag
    self.caption = caption
    self.state = 'idle'
    
    self.svg = skin.ref('bar')
    self.caption_visual = pyglet.text.Label(caption,
                          font_name='Tahoma',
                          color = (0,0,0,255),
                          font_size=11,dpi=80,
                          x=0, y=0)
    if self.size == (0,0):
      self.size = self.caption_visual.content_width+10,self.caption_visual.content_height
    self.update_rect()
  
  def get_static_draw_elements(self):
    return [self.svg,self.caption_visual]
    
  def get_dynamic_draw_elements(self):
    None
  
  def draw(self):
    self.svg.x = self.pos[0]
    self.svg.y = self.pos[1]
    self.svg.draw(self.scale)
    self.caption_visual.x = self.pos[0]+self.cap_stride
    self.caption_visual.y = self.pos[1]+5
    #self.caption_visual.draw()
    
  def update_rect(self):
    self.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1])
    
    self.scale = (float(self.size[0])/200.0,float(self.size[1])/50.0)
    self.svg.scale = (self.scale[0],self.scale[1])
    
    self.cap_stride  =  (self.size[0] - self.caption_visual.content_width)/2
  def on_mouse_move(self,x,y,dx,dy):
    pass
  def on_mouse_outside(self,x,y,dx,dy):
    pass
  
  def key_press(self,key,mod):
    pass
  def key_release(self,key,mod):
    pass
  def text(self,text):
    pass
    
  def text_motion(self,text):
    pass
    
  def on_mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    self.pos = self.pos[0]+dx,self.pos[1]+dy
    if self.on_drag:
      self.on_drag(dx,dy)
    self.update_rect()
    
class Tip(Bar):
  def __init__(self,caption,pos = (0,0),size = (0,0),skin = default_skin):
    Widget.__init__(self,caption,pos,size)
    self.pos = pos
    self.size = size
    self.caption = caption
    self.state = 'idle'
    self.svg = skin.ref('tip')
    self.caption_visual = pyglet.text.Label(caption,
                          font_name='Tahoma',
                          color = (0,0,0,255),
                          font_size=11,dpi=80,
                          x=0, y=0)
    if self.size == (0,0):
      self.size = self.caption_visual.content_width+10,self.caption_visual.content_height
    self.update_rect()
    self.visible = False
    self.consuming = False
 
  def draw(self):
    self.svg.x = self.pos[0]
    self.svg.y = self.pos[1]
    self.svg.draw(self.svg.scale)
    self.caption_visual.x = self.pos[0]+self.cap_stride
    self.caption_visual.y = self.pos[1]+2
    self.caption_visual.draw()
    
  def update_rect(self):
    self.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1])
    self.svg.scale = (float(self.size[0])/200.0,float(self.size[1])/50.0)
    
    self.cap_stride  =  (self.size[0] - self.caption_visual.content_width)/2
    
  
class Frame(Bar):
  def __init__(self,caption,layout = None,pos = (0,0),size = (0,0),skin = default_skin):
    if layout is None:
      self.layout = CentralLayout('first',(pos[0],pos[1],pos[0]+size[0],pos[1]+size[1]))      
      button1 = RadioButtonWidget(u'Редактор')
      self.layout.add_widget(button1)
    else:
      self.layout = layout
    
    self.bar = Bar(caption,pos,(size[0]+7,20))
    Bar.__init__(self,caption,pos,size)
    self.svg = skin.ref('frame')
    
    self.update_rect()
    self.widgets = []
    self.dragging = False
    self.consuming = True
    self.type = 'floating'
    
  def draw(self):
    if not self.visible: 
      return
    self.svg.x = self.pos[0]
    self.svg.y = self.pos[1]
    #self.svg.scale = self.scale
    self.svg.draw(self.svg.scale)
    self.bar.draw()
    self.layout.draw()
  
  def text(self,text):
    pass
    
  def mouse_press(self,x,y,button):
    if self.bar.hit_test(x,y):
      
      self.dragging = True
      
    if self.hit_test(x,y):
      self.layout.mouse_press(x,y,button)
      return True
      
      
  def mouse_release(self,x,y,button):
    self.layout.mouse_release(x,y,button)
    self.dragging = False
    
  def on_mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    if self.dragging:
      self.update_pos(dx,dy)
  def on_text(self,text):
    pass
    
  def update_pos(self,x,y):
    self.pos = self.pos[0]+x,self.pos[1]+y
    self.update_rect()
    
  def update_rect(self):
    self.layout.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1])
    self.layout.update_layout()
    self.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1]+25)
    self.bar.pos = (self.pos[0],self.pos[1]+self.size[1]+9)
    self.svg.scale = ((self.size[0]+5)/200.0,(self.size[1])/50.0)
    self.cap_stride  =  (self.size[0] - self.caption_visual.content_width)/2
    self.bar.update_rect()
    
class ButtonWidget(Bar):
  def __init__(self,caption,pos = (0,0),size = (0,0),on_click = None,on_click_params = None,skin = default_skin):
    Bar.__init__(self,caption,pos,size)
    self.state = 'idle'
    self.svg = skin.ref("button")#pyglet.sprite.Sprite(skin.ref('button'),blend_src=GL_SRC_ALPHA, blend_dest=GL_ONE_MINUS_SRC_ALPHA)
    self.cap_stride = 3
    self.on_click = on_click
    self.on_click_params = on_click_params

  def mouse_press(self,x,y,button):
    if self.hit_test(x,y):
      self.state = 'down'
      return True
      
  def mouse_release(self,x,y,button):
    
    if self.state == 'down':
      if self.on_click:
        if self.on_click_params:
          self.on_click(self.on_click_params)
        else:
          self.on_click()
    self.state = 'idle'
  def on_mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    pass   
    
  def get_ordered_elements(self):
    pass
    
  def draw(self):
    if self.state == 'idle':
      self.svg.x = self.pos[0]
      self.svg.y = self.pos[1]
      self.svg.draw(self.scale)
      self.caption_visual.x = self.pos[0]+self.cap_stride
      self.caption_visual.y = self.pos[1]+3
    elif self.state == 'down':
      self.svg.x = self.pos[0]+3
      self.svg.y = self.pos[1]+3
      self.svg.draw(self.scale)
      self.caption_visual.x = self.pos[0]+self.cap_stride+3
      self.caption_visual.y = self.pos[1]+6
    self.caption_visual.draw()
    pass

class PictureButton(ButtonWidget):
  def __init__(self,image,pos = (0,0),size = (0,0),on_click = None,tip = None,on_click_params = None,skin = default_skin):
    ButtonWidget.__init__(self,"",pos,size,on_click,on_click_params,skin)
    self.image = pyglet.sprite.Sprite(image,blend_src=GL_SRC_ALPHA, blend_dest=GL_ONE_MINUS_SRC_ALPHA)
    self.tip = None
    if tip is not None:
      self.tip = Tip(tip)
    self.over = 'outside'
  def on_mouse_move(self,x,y,dx,dy):
    if self.over == 'outside':
      self.over ='inside'
      self.tip.visible = True
  
  def on_mouse_outside(self,x,y,dx,dy):
    if self.over == 'inside':
      self.over ='outside'
      self.tip.visible = False
      
  def dynamic_widgets(self):
    return self.tip
    
  def draw(self):
    if self.state == 'idle':
      self.svg.x = self.pos[0]
      self.svg.y = self.pos[1]
      self.svg.draw(self.scale)
      self.image.x = self.pos[0]+3
      self.image.y = self.pos[1]+3
      #~ self.image.draw()
    elif self.state == 'down':
      self.svg.x = self.pos[0]+3
      self.svg.y = self.pos[1]+3
      self.svg.draw(self.scale)
      self.image.x = self.pos[0]+6
      self.image.y = self.pos[1]+6
      #~ self.image.draw()
      
    if self.tip is not None and self.over == "inside":
      self.tip.pos = self.pos[0]-10,self.pos[1] - 10
      #self.tip.draw()
      
class Editbox(Bar):
  def __init__(self,caption,pos = (0,0),size = (0,0),skin = default_skin):
    Bar.__init__(self,caption,pos,size)
    self.pos = pos
    self.size = size
    self.caption = caption
    self.state = 'idle'
    self.svg = skin.ref('tip')
    self.caption_visual = pyglet.text.Label(caption,
                          font_name='Tahoma',
                          color = (0,0,0,255),
                          font_size=11,dpi=80,
                          x=0, y=0)
    if self.size == (0,0):
      self.size = 150,self.caption_visual.content_height+10
    self.update_rect()
    self.visible = True
    self.consuming = True
    self.status = 'active'
    self.document = pyglet.text.document.UnformattedDocument('')
    self.document.set_style(0, len(self.document.text), 
        dict(color=(0, 0, 0, 255))
    )
    
    self.text1 = pyglet.text.layout.IncrementalTextLayout(
        self.document, 150,self.size[1]+5, multiline=False)
    self.caret = pyglet.text.caret.Caret(self.text1)
    
  def on_mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    pass   
  def focus(self):
    print 'act'
    self.status = 'active'
  
  def unfocus(self):
    print 'deact'
    self.status = 'inactive'
    
  def mouse_press(self,x,y,button):
    if self.hit_test(x,y):
      if self.state == 'active':
        self.status = 'inactive'
      else:
        self.state = 'active'
      return True
  
  def text(self,text):
    self.caret.on_text(text)
    if text == '/n':
      print 'newline'
  def text_motion(self,text):
    self.caret.on_text_motion(text)
    print text
    
  def key_press(self,key,mod):
    pass
  def mouse_release(self,x,y,button):
      return True
      
      
  def draw(self):
    self.svg.x = self.pos[0]
    self.svg.y = self.pos[1]
      
    self.svg.draw(self.svg.scale)
    
    self.text1.x = self.pos[0]+2
    self.text1.y = self.pos[1]-6
    self.text1.draw()
    
  def update_rect(self):
    self.rect = (self.pos[0],self.pos[1],self.size[0],self.size[1])
    self.svg.scale = (float(self.size[0])/200.0,float(self.size[1])/50.0)
    
    self.cap_stride  =  (self.size[0] - self.caption_visual.content_width)/2
    
class RadioButtonWidget(ButtonWidget):
  def __init__(self,caption,pos = (0,0),size = (0,0),on_click = None,on_click_params = None,skin = default_skin):
    ButtonWidget.__init__(self,caption,pos = (0,0),size = (0,0),on_click = None,on_click_params = None,skin = default_skin)
    
  def mouse_press(self,x,y,button):
    if self.hit_test(x,y):
      if self.state == 'down':
        self.state = 'idle'
      else:
        self.state = 'down'
     
  def mouse_release(self,x,y,button):
    if self.on_click:
      if self.on_click_params:
        self.on_click(self.on_click_params)
      else:
        self.on_click()
  def is_enable(self):
    return self.state == 'down'
  pass
  
